#include <cstdlib>
#include "DataProxy.h"
#include "Structures.hpp"
//#include "Request.hpp"
#include <iostream>
#include <boost/shared_ptr.hpp>


using namespace std;
using namespace netspy::db;
using namespace boost;

void queryAll(shared_ptr<DataProxy> db) {
    //get all clients
    int i = 1;
    shared_ptr<Client> c;
    while (c.get()!=NULL){
        c = db->getClient(i++);
        cout << c->ip << ", " << c->remarks << endl;
    } 
    //get all services
    cout << "getting all services" << endl;
    shared_ptr<const vector<shared_ptr<netspy::db::Service> > > v = db->getServices();
    for (vector<shared_ptr<netspy::db::Service> >::const_iterator iter = v->begin(); iter != v->end(); ++iter) {
        cout << (*iter)->id << ": " << (*iter)->description << endl;
    }
    cout << "getting pings" << endl;
    v = db->getServices("ping");
    for (vector<shared_ptr<netspy::db::Service> >::const_iterator iter = v->begin(); iter != v->end(); ++iter) {
        cout << (*iter)->id << ": " << (*iter)->description << endl;
    }
    cout << "getting services for client id=1" << endl;
    v = db->getServicesForClient(1);
    for (vector<shared_ptr<netspy::db::Service> >::const_iterator iter = v->begin(); iter != v->end(); ++iter) {
        cout << (*iter)->id << ": " << (*iter)->description << endl;
    }
    //test possible replies
    cout << "getting possible replies" << endl;
    boost::shared_ptr<const vector<shared_ptr<netspy::db::Reply> > > r = db->getReplies();
    for (vector<shared_ptr<netspy::db::Reply> >::const_iterator iter = r->begin(); iter != r->end(); ++iter) {
        cout << (*iter)->id << ", " << (*iter)->message << endl;
    }
}

int main(int argc, char** argv) {
    
    string newIP("123.143.111");
    string newHash("46FBYN");
    unsigned short newPort(70);
    string newRemark("a test driver");
    
    shared_ptr <DataProxy> db = DataProxy::getInstance();

    // DODANIE NOWEGO KOMPUTERA
    unsigned int newId = db->addClient(newIP,newPort,newHash,newRemark);
    // WERYFIKACJA
    unsigned int newId2 = db->addClient(newIP,newPort,newHash,newRemark);
    cout<<"Duplicate clients test: ";
    assert(newId == newId2);
    cout<<"OK"<<endl;
    
    //DODANIE NOWEJ USŁUGI I WERYFIKACJA POPRAWNOŚĆI DZIAŁANIA FUNKCJI PRZY PRÓBIE PONOWNEGO DODANIA
    int sid = db->addService(string("test"));
    int sid2 = db->addService(string("test"));
    cout<<"Service creation test: ";
    assert(sid==sid2);
    cout<<"OK"<<endl;
    
    //WERYFIKACJA PRZYPISANYCH USŁUG
    cout<<"Assigned services test (by id): ";
    assert((db->getServicesForClient(newId)->size())==0);
    cout<<"OK"<<endl;
            
    cout<<"Assigned services test (by hash): ";
    assert(db->getServicesForClient(newHash)->size()==0);
    cout<<"OK"<<endl;

    //DOPISANIE JAKICHŚ USŁUG.
    db->setClientService(newId,1,true);
    db->setClientService(newId,sid,true);
    cout<<"Assigned services count upon set (by hash): ";
    assert(db->getServicesForClient(newHash)->size()==2);
    cout<<"OK"<<endl;
    
    db->setClientService(newId,sid,false);
    cout<<"Assigned services count upon disabling one (by id): ";
    assert(db->getServicesForClient(newId)->size()==1);
    cout<<"OK"<<endl;
    
    db->setClientService(newHash,sid,true);
    cout<<"Assigned services count upon re0enabling one (by id): ";
    assert(db->getServicesForClient(newId)->size()==2);
    cout<<"OK"<<endl;
    
    cout<<"Will insert some records about services availability"<<endl;
    //get the Replies
    shared_ptr<const vector<shared_ptr<Reply> > > r = db->getReplies();
    int alive=0, dead=0, none=0;
    for (vector<shared_ptr<netspy::db::Reply> >::const_iterator iter = r->begin(); iter != r->end(); ++iter) {
        if((*iter)->message.compare(string("alive"))==0){
            alive=(*iter)->id;
            cout<<"alive: "<<alive<<endl;
        }else if((*iter)->message.compare(string("dead"))==0){
            dead=(*iter)->id;
            cout<<"dead: "<<dead<<endl;
        }else{
            none=(*iter)->id;
            cout<<"none: "<<none<<endl;
        }
    }
    
    for(int i=0; i<100; ++i){
        if(rand()<RAND_MAX*0.75){
            if(rand()>RAND_MAX*0.7){
                db->addRecord(newId,(*db->getServicesForClient(newHash)->begin())->id,none);
            }else{
                db->addRecord(newId,(*db->getServicesForClient(newHash)->begin())->id,alive);
            }
        }else{
            db->addRecord(newId,(*db->getServicesForClient(newHash)->begin())->id,dead);
        }
        sleep(1);
    }
    
    cout<<"Hit enter to delete the newly added data and proceed with tests"<<endl;
    cin.ignore(1);
    
    //USUNIĘCIE NOWO DODANEGO KLIENTA I WSZYSTKICH JEGO DANYCH
    db->deleteClientsData(newId);
    cout<<"Get client by id upon deletion: ";
    assert(db->getClient(newId).get()==NULL);
    cout<<"OK"<<endl;
    
    cout<<"Get client by hash upon deletion: ";
    assert(db->getClient(newHash).get()==NULL);
    cout<<"OK"<<endl;
    
    //WERYFIKACJA PRZYPISANYCH USŁUG
    cout<<"Assigned services upon deletion test (by id): ";
    assert((db->getServicesForClient(newId)->size())==0);
    cout<<"OK"<<endl;
            
    cout<<"Assigned services upon deletion test (by hash): ";
    assert(db->getServicesForClient(newHash)->size()==0);
    cout<<"OK"<<endl;
    
    return 0;

}

